package com.atguigu.tingshu.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.model.user.*;
import com.atguigu.tingshu.user.config.WechatAccountConfig;
import com.atguigu.tingshu.user.factory.StrategyFactory;
import com.atguigu.tingshu.user.mapper.*;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.atguigu.tingshu.user.strategy.ItemTypeStrategy;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

	@Autowired
	private UserInfoMapper userInfoMapper;
	@Autowired
	private WechatAccountConfig wechatAccountConfig;

	@Autowired
	private WxMaService wxMaService;

	@Autowired
	private RedisTemplate redisTemplate;

	@Autowired
	private RabbitService rabbitService;

	@Autowired
	private UserPaidAlbumMapper userPaidAlbumMapper;

	@Autowired
	private UserPaidTrackMapper userPaidTrackMapper;

	@Autowired
	private TrackInfoFeignClient trackInfoFeignClient;

    @Autowired
    private UserVipServiceMapper userVipServiceMapper;

	@Autowired
	private VipServiceConfigMapper vipServiceConfigMapper;

	@Autowired
	private StrategyFactory strategyFactory;


	@Override
	public Map<String, Object> wxLogin(String code) {
        WxMaJscode2SessionResult wxMaJscode2SessionResult = null;
        try {
            wxMaJscode2SessionResult = wxMaService.jsCode2SessionInfo(code);
        } catch (WxErrorException e) {
            throw new RuntimeException(e);
        }
        //openid：每个人微信对应的唯一标识。唯一标识在数据库中有，说明登录过了。没有说明没登录
		String openid = wxMaJscode2SessionResult.getOpenid();
		//利用openid实现登录或注册功能，看userinfo表中有没有openid，如果有就说明有信息就登陆，没有就说明需要注册
		UserInfo userInfo = userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getWxOpenId, openid));
		if(userInfo==null){
			//注册,本质是赋值
			userInfo=new UserInfo();//如果没有new，则userinfo是null，会发生空指针异常，没有空间去存值
			userInfo.setWxOpenId(openid);
			userInfo.setNickname("听友:" + System.currentTimeMillis());
			userInfo.setAvatarUrl("https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
			//数据保存到数据库
			userInfoMapper.insert(userInfo);
			//首次注册，给当前注册的用户进行初始化充值
			//此处有两种方法；1.使用openfeign（同步），如果没有给账户充值是不会注册成功的，不合理，怎么样也要在系统下留下客户信息
			//2.使用rabbitmq发送消息（异步），userid作为消息内容，即使账户没有立马拿到100，也能登录，即使用户没拿到100但也留住了客户信息.
			rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_USER_REGISTER,userInfo.getId());

		}
		//登录，将数据存到redis中且返回token
		String token= UUID.randomUUID().toString().replaceAll("-","");
		//组成缓存的key
		String userLoginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
		//存储数据
		redisTemplate.opsForValue().set(userLoginKey,userInfo,RedisConstant.USER_LOGIN_KEY_TIMEOUT, TimeUnit.SECONDS);

		//返回数据
		HashMap<String, Object> map = new HashMap<>();
		map.put("token",token);
		return map;
	}

	@Override
	public UserInfoVo getUserInfo(Long userId) {
		//  查询用户信息
		UserInfo userInfo = this.getById(userId);
		//  创建一个目标对象
		UserInfoVo userInfoVo = new UserInfoVo();
		//  属性拷贝：
		BeanUtils.copyProperties(userInfo, userInfoVo);
		return userInfoVo;
	}

	@Override
	public void updateUser(Long userId, UserInfoVo userInfoVo) {
		//  修改用户信息;
		UserInfo userInfo = new UserInfo();
		//  属性拷贝:
		BeanUtils.copyProperties(userInfoVo, userInfo);
		userInfo.setId(userId);
		this.updateById(userInfo);
	}

	/**
	 * 判断用户是否购买声音列表
	 * @param albumId
	 * @param trackIdList
	 * @return
	 */
	@Override
	public Map<Long, Integer> userIsPaidTrack(Long albumId, List<Long> trackIdList,Long userId) {
		//  创建map 集合（设置为全部没有购买过，0为未购买，1为已购买）
		Map<Long, Integer> map = trackIdList.stream().collect(Collectors.toMap(trackId -> trackId, trackId -> 0));
		//判断用户是否购买了整个专辑，如果购买了整个专辑则遍历把整个列表的声音设置为1
		UserPaidAlbum userPaidAlbum = userPaidAlbumMapper.selectOne(new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getUserId, userId).eq(UserPaidAlbum::getAlbumId, albumId));
		if(userPaidAlbum !=null){
			//说明购买了专辑,将声音列表设置为1
			return trackIdList.stream().collect(Collectors.toMap(trackId -> trackId, trackId -> 1));
		}
		//说明没有购买专辑，则去查找购买的声音，将购买过的声音设置为1
		List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(new LambdaQueryWrapper<UserPaidTrack>().eq(UserPaidTrack::getUserId, userId).in(UserPaidTrack::getTrackId, trackIdList));
		//购买的声音列表不为空说明用户购买过声音，循环遍历，将这些购买的声音添加到map中
		if(!CollectionUtils.isEmpty(userPaidTrackList)){
			for (UserPaidTrack userPaidTrack : userPaidTrackList) {
				map.put(userPaidTrack.getTrackId(), 1);
			}
		}
		//返回数据
		return map;
	}

	/**
	 * 判断用户是否购买过专辑
	 * @param albumId
	 * @param userId
	 * @return
	 */
	@Override
	public Boolean isPaidAlbum(Long albumId, Long userId) {
		//查看当前用户是否购买过专辑;
		return userPaidAlbumMapper.selectCount(new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getUserId,userId).eq(UserPaidAlbum::getAlbumId,albumId))>0;

	}

	/**
	 * 获取专辑id已支付的声音Id集合列表
	 * @param albumId
	 * @param userId
	 * @return
	 */
	@Override
	public List<Long> findUserPaidTrackList(Long albumId, Long userId) {
		//select * from user_paid_track where albumId=? and userId=? and is_deleted=0;
		List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(new LambdaQueryWrapper<UserPaidTrack>().eq(UserPaidTrack::getAlbumId, albumId)
				.eq(UserPaidTrack::getUserId, userId)
				.eq(UserPaidTrack::getIsDeleted, 0));

		List<Long> userPaidTrackIdList = userPaidTrackList.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());
		return userPaidTrackIdList;
	}

	/**
	 * 处理用户购买记录
	 * @param userPaidRecordVo
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void savePaidRecord(UserPaidRecordVo userPaidRecordVo) {

		//  返回策略对象
		ItemTypeStrategy itemTypeStrategy = strategyFactory.getStrategy(userPaidRecordVo.getItemType());
		itemTypeStrategy.savePaidRecord(userPaidRecordVo);

		/*//判断购买类型
		if(SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(userPaidRecordVo.getItemType())){
			//购买的是专辑  user_paid_album
			//先判断用户是否买过这个专辑
			UserPaidAlbum userPaidAlbum = userPaidAlbumMapper.selectOne(new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getUserId, userPaidRecordVo.getUserId()).eq(UserPaidAlbum::getAlbumId, userPaidRecordVo.getItemIdList().get(0)));
			if(null!=userPaidAlbum){
				//表中有数据，说明用户买过此专辑，直接返回
				return;
			}
			//说明用户没有买过
			//创建对象赋值
			userPaidAlbum = new UserPaidAlbum();
			userPaidAlbum.setUserId(userPaidRecordVo.getUserId());
			userPaidAlbum.setOrderNo(userPaidRecordVo.getOrderNo());
			userPaidAlbum.setAlbumId(userPaidRecordVo.getItemIdList().get(0));
			//  保存数据;
			userPaidAlbumMapper.insert(userPaidAlbum);

		} else if (SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(userPaidRecordVo.getItemType())) {
			//购买的是声音
			//声音 user_paid_track; 判断当前购买的声音Id在当前表中是否存在！
			//用户要购买的声音列表;
			List<Long> itemIdList = userPaidRecordVo.getItemIdList();

			//用户在已购买的列表中买了对应的声音
			LambdaQueryWrapper<UserPaidTrack> wrapper = new LambdaQueryWrapper<>();
			wrapper.eq(UserPaidTrack::getUserId,userPaidRecordVo.getUserId())
					.in(UserPaidTrack::getId,itemIdList);
			List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(wrapper);

			//转成set集合，通过trackId 判断是否存在
			//从用户已有的购买记录列表（userPaidTrackList）中，提取所有已购买的声音 ID（trackId），并存储到Set集合中
			//利用Set的快速查找特性（contains方法），高效判断某个声音是否已被购买
			Set<Long> paidTrackIdSet = userPaidTrackList.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toSet());
			//  根据声音Id获取声音对象;
			Result<TrackInfo> trackInfoResult = trackInfoFeignClient.getTrackInfo(userPaidRecordVo.getItemIdList().get(0));
			Assert.notNull(trackInfoResult, "查询声音信息失败");
			TrackInfo trackInfo = trackInfoResult.getData();
			Assert.notNull(trackInfo, "查询声音信息失败");
			if(!CollectionUtils.isEmpty(userPaidTrackList)){
				//说明要买的声音中存在已经买过的
				for (Long itemId : itemIdList) {
					if(paidTrackIdSet.contains(itemId)){
						//说明是买过的声音，直接进入下一个循环
						continue;
					}
					UserPaidTrack userPaidTrack = new UserPaidTrack();
					userPaidTrack.setOrderNo(userPaidRecordVo.getOrderNo());
					userPaidTrack.setUserId(userPaidRecordVo.getUserId());
					userPaidTrack.setAlbumId(trackInfo.getAlbumId());
					userPaidTrack.setTrackId(itemId);
					//保存数据
					userPaidTrackMapper.insert(userPaidTrack);
				}
				return;
			}

			//说明要买的集合中全部是没有买过得声音
			for (Long trackId : itemIdList) {
				//说明没有购买过
				UserPaidTrack userPaidTrack = new UserPaidTrack();
				userPaidTrack.setOrderNo(userPaidRecordVo.getOrderNo());
				userPaidTrack.setUserId(userPaidRecordVo.getUserId());
				userPaidTrack.setAlbumId(trackInfo.getAlbumId());
				userPaidTrack.setTrackId(trackId);
				//保存数据
				userPaidTrackMapper.insert(userPaidTrack);
			}

		}else {
			//购买的是vip,判断是第一次买还是续期
			//通过id拿数据
			Long vipServiceId = userPaidRecordVo.getItemIdList().get(0);
			VipServiceConfig vipServiceConfig = vipServiceConfigMapper.selectById(vipServiceId);
			//获取到购买时长
			Integer serviceMonth = vipServiceConfig.getServiceMonth();
			//创建对象
			UserVipService userVipService = new UserVipService();
			//赋值
			userVipService.setUserId(userPaidRecordVo.getUserId());
			userVipService.setOrderNo(userPaidRecordVo.getOrderNo());
			//userVipService.setStartTime(new Date());
			//到期时间，判断是第一次买还是续期
			UserInfo userInfo = userInfoMapper.selectById(userPaidRecordVo.getUserId());
			//是vip且vip没有过期
			//Date expireTime =null;
			Date currentTime = new Date();
			if(userInfo.getIsVip()==1 && userInfo.getVipExpireTime().after(new Date())){
//				//在购买vip就是续期
//				LocalDateTime localDateTime = new LocalDateTime(userInfo.getVipExpireTime());
//				expireTime = localDateTime.plusMonths(serviceMonth).toDate();
//				userVipService.setExpireTime(expireTime);
				currentTime=userInfo.getVipExpireTime();

//			}else {
//				//是第一次购买，当前时间+购买时间
//				userVipService.setExpireTime(new LocalDateTime(new Date()).plusMonths(serviceMonth).toDate());
			}

			//创建对象（LocalDateTime线程安全）
			LocalDateTime localDateTime = new LocalDateTime(currentTime);
			//获取过期时间
			Date expireTime = localDateTime.plusMonths(serviceMonth).toDate();
			//设置过期时间
			userVipService.setExpireTime(expireTime);
			//保存购买记录
			userVipServiceMapper.insert(userVipService);
			//购买了vip，需要更新用户的vip状态
			userInfo.setIsVip(1);
			userInfo.setVipExpireTime(expireTime);
			this.updateById(userInfo);
		}
*/

	}
}
